package cn.net.xinyi.xs.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.i18n.LocaleContextHolder;

import cn.net.xinyi.xs.Constants;

/**
 * Date Utility Class used to convert Strings to Dates and Timestamps
 * 
 * @author <a href="mailto:caihualin2009@gmail.com">Cai Hua</a> to correct time
 *         pattern. Minutes should be mm not MM (MM is month).
 */
public class DateUtil {
	private static Log log = LogFactory.getLog(DateUtil.class);
	private static final String TIME_PATTERN = "HH:mm";

	/**
	 * Checkstyle rule: utility classes should not have public constructor
	 */
	private DateUtil() {
	}

	/**
	 * Return default datePattern (MM/dd/yyyy)
	 * 
	 * @return a string representing the date pattern on the UI
	 */
	public static String getDatePattern() {
		Locale locale = LocaleContextHolder.getLocale();
		String defaultDatePattern;
		try {
			defaultDatePattern = ResourceBundle.getBundle(Constants.BUNDLE_KEY,
					locale).getString("date.format");
		} catch (MissingResourceException mse) {
			defaultDatePattern = "MM/dd/yyyy";
		}

		return defaultDatePattern;
	}

	public static String getDateTimePattern() {
		return DateUtil.getDatePattern() + " HH:mm:ss.S";
	}

	/**
	 * This method attempts to convert an Oracle-formatted date in the form
	 * dd-MMM-yyyy to mm/dd/yyyy.
	 * 
	 * @param aDate
	 *            date from database as a string
	 * @return formatted string for the ui
	 */
	public static String getDate(Date aDate) {
		SimpleDateFormat df;
		String returnValue = "";

		if (aDate != null) {
			df = new SimpleDateFormat(getDatePattern());
			returnValue = df.format(aDate);
		}

		return (returnValue);
	}

	/**
	 * This method generates a string representation of a date/time in the
	 * format you specify on input
	 * 
	 * @param aMask
	 *            the date pattern the string is in
	 * @param strDate
	 *            a string representation of a date
	 * @return a converted Date object
	 * @see java.text.SimpleDateFormat
	 * @throws ParseException
	 *             when String doesn't match the expected format
	 */
	public static Date convertStringToDate(String aMask, String strDate)
			throws ParseException {
		SimpleDateFormat df;
		Date date;
		df = new SimpleDateFormat(aMask);

		if (log.isDebugEnabled()) {
			log.debug("converting '" + strDate + "' to date with mask '"
					+ aMask + "'");
		}

		try {
			date = df.parse(strDate);
		} catch (ParseException pe) {
			// log.error("ParseException: " + pe);
			throw new ParseException(pe.getMessage(), pe.getErrorOffset());
		}

		return (date);
	}

	/**
	 * This method returns the current date time in the format: MM/dd/yyyy HH:MM
	 * a
	 * 
	 * @param theTime
	 *            the current time
	 * @return the current date/time
	 */
	public static String getTimeNow(Date theTime) {
		return getDateTime(TIME_PATTERN, theTime);
	}

	/**
	 * This method returns the current date in the format: MM/dd/yyyy
	 * 
	 * @return the current date
	 * @throws ParseException
	 *             when String doesn't match the expected format
	 */
	public static Calendar getToday() throws ParseException {
		Date today = new Date();
		SimpleDateFormat df = new SimpleDateFormat(getDatePattern());

		// This seems like quite a hack (date -> string -> date),
		// but it works ;-)
		String todayAsString = df.format(today);
		Calendar cal = new GregorianCalendar();
		cal.setTime(convertStringToDate(todayAsString));

		return cal;
	}

	/**
	 * This method generates a string representation of a date's date/time in
	 * the format you specify on input
	 * 
	 * @param aMask
	 *            the date pattern the string is in
	 * @param aDate
	 *            a date object
	 * @return a formatted string representation of the date
	 * 
	 * @see java.text.SimpleDateFormat
	 */
	public static String getDateTime(String aMask, Date aDate) {
		SimpleDateFormat df = null;
		String returnValue = "";

		if (aDate == null) {
			log.error("aDate is null!");
		} else {
			df = new SimpleDateFormat(aMask);
			returnValue = df.format(aDate);
		}

		return (returnValue);
	}

	/**
	 * This method generates a string representation of a date based on the
	 * System Property 'dateFormat' in the format you specify on input
	 * 
	 * @param aDate
	 *            A date to convert
	 * @return a string representation of the date
	 */
	public static String convertDateToString(Date aDate) {
		return getDateTime(getDatePattern(), aDate);
	}

	/**
	 * This method converts a String to a date using the datePattern
	 * 
	 * @param strDate
	 *            the date to convert (in format MM/dd/yyyy)
	 * @return a date object
	 * @throws ParseException
	 *             when String doesn't match the expected format
	 */
	public static Date convertStringToDate(String strDate)
			throws ParseException {
		Date aDate = null;

		try {
			if (log.isDebugEnabled()) {
				log.debug("converting date with pattern: " + getDatePattern());
			}

			aDate = convertStringToDate(getDatePattern(), strDate);
		} catch (ParseException pe) {
			log.error("Could not convert '" + strDate
					+ "' to a date, throwing exception");
			pe.printStackTrace();
			throw new ParseException(pe.getMessage(), pe.getErrorOffset());
		}

		return aDate;
	}

	public static Date convertStringToDateTime(String strDate)
			throws ParseException {
		Date aDate = null;
		try {
			if (log.isDebugEnabled()) {
				log.debug("converting date with pattern: " + getDatePattern());
			}
			aDate = convertStringToDate(
					DateUtil.getDatePattern() + " HH:mm:ss", strDate);
		} catch (ParseException pe) {
			log.error("Could not convert '" + strDate
					+ "' to a date, throwing exception");
			pe.printStackTrace();
			throw new ParseException(pe.getMessage(), pe.getErrorOffset());
		}
		return aDate;
	}

	public static Date getWeekStartTime(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
		try {
			return convertStringToDateTime(new SimpleDateFormat("yyyy-MM-dd")
					.format(calendar.getTime())
					+ " 00:00:00");
		} catch (ParseException e) {
			return date;
		}
	}

	public static Date getMonthStartTime(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(GregorianCalendar.DAY_OF_MONTH, 1);
		try {
			return convertStringToDateTime(new SimpleDateFormat("yyyy-MM-dd")
					.format(calendar.getTime())
					+ " 00:00:00");
		} catch (ParseException e) {
			return date;
		}
	}

	public static Date getDayStartTime(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		try {
			return convertStringToDateTime(new SimpleDateFormat("yyyy-MM-dd")
					.format(calendar.getTime())
					+ " 00:00:00");
		} catch (ParseException e) {
			e.printStackTrace();
			return null;
		}
	}

	// ��ȡ�ꡢ�»��ܵ���ʼʱ��

	public static String getStartTime(int year, int month, int week) {
		Calendar calendar = new GregorianCalendar();
		if (year == 0) {
			return null;
		} else {
			if (week == 0 && month != 0) {
				calendar.set(Calendar.YEAR, year);
				calendar.set(Calendar.MONTH, month - 1);
				calendar.set(Calendar.DATE, 1);

				/*
				 * //Calendar.HOUR_OF_DAY
				 * 
				 * calendar.set(Calendar.HOUR_OF_DAY, 0);
				 * 
				 * calendar.set(Calendar.MINUTE, 0);
				 * 
				 * calendar.set(Calendar.SECOND, 0);
				 */
			} else if (week == 0 && month == 0) {
				calendar.set(Calendar.YEAR, year);
				calendar.set(Calendar.MONTH, 0);
				calendar.set(Calendar.DATE, 1);

				/*
				 * calendar.set(Calendar.HOUR_OF_DAY, 0);
				 * 
				 * calendar.set(Calendar.MINUTE, 0);
				 * 
				 * calendar.set(Calendar.SECOND, 0);
				 */

			} else {
				Calendar c = new GregorianCalendar();
				c.set(Calendar.YEAR, year);
				c.set(Calendar.MONTH, Calendar.JANUARY);
				c.set(Calendar.DATE, 1);
				c.setFirstDayOfWeek(Calendar.MONDAY);
				c.setMinimalDaysInFirstWeek(7);
				Calendar cal = (GregorianCalendar) c.clone();
				cal.add(Calendar.DATE, week * 7);
				calendar.setFirstDayOfWeek(Calendar.MONDAY);
				calendar.setTime(cal.getTime());
				calendar.setMinimalDaysInFirstWeek(7);
				calendar.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek());
			}
			return new SimpleDateFormat("yyyy-MM-dd 00:00:00").format(calendar
					.getTime());
		}
	}

	// ��ȡ�ꡢ�»��ܵĽ���ʱ��

	public static String getEndTime(int year, int month, int week) {
		Calendar calendar = new GregorianCalendar();
		if (year == 0) {
			return null;
		} else {
			if (week == 0 && month != 0) {
				calendar.set(Calendar.YEAR, year);
				calendar.set(Calendar.MONTH, month - 1);
				calendar.set(Calendar.DATE, getDaysOfMonth(year, month));
			} else if (week == 0 && month == 0) {
				calendar.set(Calendar.YEAR, year);
				calendar.set(Calendar.MONTH, 11);
				calendar.set(Calendar.DATE, getDaysOfMonth(year, 12));
			} else {
				Calendar c = new GregorianCalendar();
				c.set(Calendar.YEAR, year);
				c.set(Calendar.MONTH, Calendar.JANUARY);
				c.set(Calendar.DATE, 1);
				c.setFirstDayOfWeek(Calendar.MONDAY);
				c.setMinimalDaysInFirstWeek(7);
				Calendar cal = (GregorianCalendar) c.clone();
				cal.add(Calendar.DATE, week * 7);
				calendar.setFirstDayOfWeek(Calendar.MONDAY);
				calendar.setTime(cal.getTime());
				calendar.setMinimalDaysInFirstWeek(7);
				calendar.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek() + 6);
			}
			return new SimpleDateFormat("yyyy-MM-dd 23:59:59").format(calendar
					.getTime());
		}

	}

	// ��ȡĳ�µ�����
	private static int getDaysOfMonth(int year, int month) {
		Calendar calendar = new GregorianCalendar();
		calendar.set(Calendar.YEAR, year);
		calendar.set(Calendar.MONTH, month - 1);
		calendar.setFirstDayOfWeek(Calendar.SUNDAY);
		calendar.setMinimalDaysInFirstWeek(3);
		return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
	}

	// ��ȡĳ�µ���ʼ��
	public static int getStartWeekOfMonth(int year, int month) {
		if (month == 1)
			return 1;
		return getEndWeekOfMonth(year, month - 1);
	}

	// ��ȡĳ�µ�����
	private static int getWeeksOfMonth(int year, int month) {
		Calendar c = new GregorianCalendar();
		c.set(Calendar.YEAR, year);
		c.set(Calendar.MONTH, month - 1);
		c.set(Calendar.DATE, 1);
		c.setFirstDayOfWeek(Calendar.MONDAY);
		c.setMinimalDaysInFirstWeek(7);
		Calendar cal = (GregorianCalendar) c.clone();
		cal.setFirstDayOfWeek(Calendar.MONDAY);
		cal.setMinimalDaysInFirstWeek(7);
		cal.setTime(c.getTime());
		int num = cal.getActualMaximum(Calendar.WEEK_OF_MONTH);
		return num;
	}

	// ��ȡĳ�µĽ�����
	public static int getEndWeekOfMonth(int year, int month) {
		int endWeek = 0;
		if (month < 12) {
			for (int i = 1; i <= month; i++) {
				endWeek += getWeeksOfMonth(year, i);
			}
			return endWeek + 1;
		} else {
			for (int i = 1; i <= 12; i++) {
				endWeek += getWeeksOfMonth(year, i);
			}
			return endWeek;
		}
	}

	// ��ȡһ��ǰ
	public static Date lastWeek() {
		Date date = new Date();
		int year = Integer.parseInt(new SimpleDateFormat("yyyy").format(date));
		int month = Integer.parseInt(new SimpleDateFormat("MM").format(date));
		int day = Integer.parseInt(new SimpleDateFormat("dd").format(date)) - 6;
		if (day < 1) {
			month -= 1;
			if (month == 0) {
				year -= 1;
				month = 12;
			}
			if (month == 4 || month == 6 || month == 9 || month == 11) {
				day = 30 + day;
			} else if (month == 1 || month == 3 || month == 5 || month == 7
					|| month == 8 || month == 10 || month == 12) {
				day = 31 + day;
			} else if (month == 2) {
				if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) {
					day = 29 + day;
				} else {
					day = 28 + day;
				}
			}
		}
		String y = year + "";
		String m = "";
		String d = "";
		if (month < 10) {
			m = "0" + month;
		} else {
			m = month + "";
		}
		if (day < 10) {
			d = "0" + day;
		} else {
			d = day + "";
		}
		try {
			return (new SimpleDateFormat("yyyy-MM-dd hh:mm:ss")).parse(y + "-"
					+ m + "-" + d + " 00:00:00");
		} catch (ParseException e) {
			e.printStackTrace();
			return null;
		}
	}

	// ��ȡһ��ǰ
	public static Date lastMonth() {
		Date date = new Date();
		int year = Integer.parseInt(new SimpleDateFormat("yyyy").format(date));
		int month = Integer.parseInt(new SimpleDateFormat("MM").format(date)) - 1;
		int day = Integer.parseInt(new SimpleDateFormat("dd").format(date));
		if (month == 0) {
			year -= 1;
			month = 12;
		} else if (day > 28) {
			if (month == 2) {
				if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) {
					day = 29;
				} else {
					day = 28;
				}
			} else if ((month == 4 || month == 6 || month == 9 || month == 11)
					&& day == 31) {
				day = 30;
			}
		}
		String y = year + "";
		String m = "";
		String d = "";
		if (month < 10) {
			m = "00" + month;
		} else {
			m = month + "";
		}
		if (day < 10) {
			d = "0" + day;
		} else {
			d = day + "";
		}
		try {
			return (new SimpleDateFormat("yyyy-MM-dd hh:mm:ss")).parse(y + "-"
					+ m + "-" + d + " 00:00:00");
		} catch (ParseException e) {
			e.printStackTrace();
			return null;
		}
	}

	public static String convertDateTimeToString(Date aDate) {
		return getDateTime(DateUtil.getDatePattern() + " HH:mm:ss", aDate);
	}

	public static String getStartTimeOfPolic(int year, int month) {
		Calendar calendar = new GregorianCalendar();
		if (year == 0) {
			return null;
		} else {
			if (month != 0) {
				calendar.set(Calendar.YEAR, year);
				calendar.set(Calendar.MONTH, month - 2);
				calendar.set(Calendar.DATE, 25);
			} else {
				calendar.set(Calendar.YEAR, year);
				calendar.set(Calendar.MONTH, 0);
				calendar.set(Calendar.DATE, 25);
			}
			return new SimpleDateFormat("yyyy-MM-dd 00:00:00").format(calendar
					.getTime());
		}
	}

	public static String getEndTimeOfPolic(int year, int month) {
		Calendar calendar = new GregorianCalendar();
		if (year == 0) {
			return null;
		} else {
			if (month != 0) {
				calendar.set(Calendar.YEAR, year);
				calendar.set(Calendar.MONTH, month - 1);
				calendar.set(Calendar.DATE, 25);
			} else {
				calendar.set(Calendar.YEAR, year);
				calendar.set(Calendar.MONTH, 12);
				calendar.set(Calendar.DATE, 25);
			}
			return new SimpleDateFormat("yyyy-MM-dd 23:59:59").format(calendar
					.getTime());
		}
	}

	public static Date boforeTime() {
		Date now = new Date();
		long time = now.getTime() - 5 * 60 * 1000;
		Date timeBefore = new Date(time);
		return timeBefore;
	}
	
	public static void main(String[] args) {
		System.out.println(getStartTimeOfPolic(2011, 2));
		System.out.println(getEndTimeOfPolic(2011, 2));

		System.out.println("start:  " + getStartTimeOfPolic(2011, 12));
		System.out.println("end:  " + getEndTimeOfPolic(2011, 12));
		System.out.println("15   " + boforeTime());
	}
}
